package imp

import (
	cache "bgs/cache/op"
	sqlc "bgs/db/sqlc"
	orderGrpc "bgs/grpc/gen/service/order"
	"bgs/grpc/gen/shared/message"
	"bgs/grpc/imp/enums"
	"bgs/service/model"
	orderService "bgs/service/order"
	paymentService "bgs/service/payment"
	"bgs/util"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"time"
)

/****************************************************************************************/
/*                               order entity of helper                                 */
/****************************************************************************************/

func transformOrderEntityToPb(orderExtInfoPtr *model.OrderExtInfo, enforcementPtr *sqlc.Enforcement) func(o sqlc.Order) *orderGrpc.OrderEntity {
	return func(o sqlc.Order) *orderGrpc.OrderEntity {
		orderEntityPtr := &orderGrpc.OrderEntity{
			Id:                  o.ID,
			Ordered:             sqlc.GoTimeToPBTimestamp(o.Ordered),
			SerialNumber:        o.SerialNumber,
			BrandId:             o.BrandID,
			StoreId:             o.StoreID.Int64,
			DistributorId:       o.DistributorID.Int64,
			DistributorUserId:   o.DistributorUserID.Int64,
			ActivityId:          o.ActivityID,
			UserId:              o.UserID,
			UserOpenId:          o.UserOpenID,
			SpokesmanId:         o.SpokesmanID.Int64,
			SpokesmanUserId:     o.SpokesmanUserID.Int64,
			OrderType:           o.OrderType,
			OrderStatus:         o.OrderStatus,
			DeliveryMode:        o.DeliveryMode,
			Remark:              o.Remark.String,
			PaymentDeadlineAt:   sqlc.GoTimeToPBTimestamp(o.PaymentDeadlineAt),
			Cancelled:           sqlc.GoNTimeToPBTimestamp(o.Cancelled),
			CancelReason:        o.CancelReason.String,
			Finished:            sqlc.GoNTimeToPBTimestamp(o.Finished),
			AfterSaleDeadlineAt: sqlc.GoNTimeToPBTimestamp(o.AfterSaleDeadlineAt),
			ShippingAddress:     string(sqlc.NRawMessageToRawMessage(o.ShippingAddress)),
			ShippingFee:         o.ShippingFee,
			ProductAmount:       o.ProductAmount,
			Amount:              o.Amount,
			ActualAmount:        o.ActualAmount,
			IsApplyForAfterSale: o.IsApplyForAfterSale,
			IsInAfterSale:       o.IsInAfterSale,
			OrderDetails:        mapOrderDetailEntityToPb(orderExtInfoPtr.Details, transformOrderDetailEntityToPb),
			BrandName:           orderExtInfoPtr.BrandName,
			BrandPic:            orderExtInfoPtr.BrandPic,
			BrandTel:            orderExtInfoPtr.BrandTel,
			StoreName:           orderExtInfoPtr.StoreName,
			StorePic:            orderExtInfoPtr.StorePic,
			StoreTel:            orderExtInfoPtr.StoreTel,
			ActivityOwner:       orderExtInfoPtr.ActivityOwner,
			ActivityName:        orderExtInfoPtr.ActivityName,
			ActivityTel:         orderExtInfoPtr.ActivityTel,
			ParentActivityOwner: orderExtInfoPtr.ParentActivityOwner,
			ParentActivityName:  orderExtInfoPtr.ParentActivityName,
			ParentActivityTel:   orderExtInfoPtr.ParentActivityTel,
			BuyerNickName:       orderExtInfoPtr.BuyerNickName,
			BuyerPic:            orderExtInfoPtr.BuyerPic,
			BuyerTel:            orderExtInfoPtr.BuyerTel,
		}

		if o.DeliveryMode == string(sqlc.EmDeliveryModeSelfPickup) {

			orderEntityPtr.SelfPickInfo = &orderGrpc.SelfPickInfo{
				Address: orderExtInfoPtr.WarehouseInfo.Address,
				Linkman: orderExtInfoPtr.WarehouseInfo.Linkman,
				Tel:     orderExtInfoPtr.WarehouseInfo.Tel,
			}

			if enforcementPtr != nil {
				orderEntityPtr.SelfPickInfo.Code = enforcementPtr.PickupCode.String
			}

		} else if o.DeliveryMode == string(sqlc.EmDeliveryModeExpress) {
			shippingLogisticsInfoPtr := &model.LogisticsInfo{}
			if enforcementPtr != nil {
				if enforcementPtr.ShippingLogisticsInfo.Valid {
					json.Unmarshal(enforcementPtr.ShippingLogisticsInfo.RawMessage, shippingLogisticsInfoPtr)
				}
			}
			orderEntityPtr.DeliverInfo = &message.LogisticsInfo{
				Platform:         shippingLogisticsInfoPtr.Platform,
				PlatformOrderNum: shippingLogisticsInfoPtr.PlatformOrderNum,
			}
		}

		return orderEntityPtr
	}
}

func transformOrderDetailEntityToPb(
	o *model.OrderDetailInExtInfo,
) *orderGrpc.OrderDetailItemEntity {
	return &orderGrpc.OrderDetailItemEntity{
		Id:                  o.OrderDetailID,
		ProductId:           o.ProductID,
		ProductName:         o.ProductName,
		ProductSpecId:       o.ProductSpecID,
		ProductSpecKey:      o.ProductSpecKey,
		ProductSpecName:     o.ProductSpecName,
		ProductWithSpecName: o.ProductWithSpecName,
		StorageKey:          o.StorageKey,
		ProductPics:         o.ProductPics,
		Quantity:            o.Quantity,
		Price:               o.Price,
	}
}

func mapOrderDetailEntityToPb(list []*model.OrderDetailInExtInfo, f func(*model.OrderDetailInExtInfo) *orderGrpc.OrderDetailItemEntity) []*orderGrpc.OrderDetailItemEntity {
	r := make([]*orderGrpc.OrderDetailItemEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformOrderItemForCEntityToPb(o sqlc.Order) *orderGrpc.OrderItemForCEntity {
	orderExtInfo := &model.OrderExtInfo{}
	json.Unmarshal(o.ExtInfo, orderExtInfo)
	var ownerName, ownerPic, ownerTel string
	if o.StoreID.Valid {
		ownerName = orderExtInfo.StoreName
		ownerPic = orderExtInfo.StorePic
		ownerTel = orderExtInfo.StoreTel
	} else {
		ownerName = orderExtInfo.BrandName
		ownerPic = orderExtInfo.BrandPic
		ownerTel = orderExtInfo.BrandTel
	}
	return &orderGrpc.OrderItemForCEntity{
		Id:                o.ID,
		Ordered:           sqlc.GoTimeToPBTimestamp(o.Ordered),
		SerialNumber:      o.SerialNumber,
		BrandId:           o.BrandID,
		StoreId:           o.StoreID.Int64,
		DistributorId:     o.DistributorID.Int64,
		DistributorUserId: o.DistributorUserID.Int64,
		ActivityId:        o.ActivityID,
		OrderType:         o.OrderType,
		OrderStatus:       o.OrderStatus,
		DeliveryMode:      o.DeliveryMode,
		Amount:            o.Amount,
		PaymentDeadlineAt: sqlc.GoTimeToPBTimestamp(o.PaymentDeadlineAt),
		OrderDetails:      mapOrderDetailEntityToPb(orderExtInfo.Details, transformOrderDetailEntityToPb),
		OwnerName:         ownerName,
		OwnerPic:          ownerPic,
		OwnerTel:          ownerTel,
		ActivityName:      orderExtInfo.ActivityName,
		ActivityTel:       orderExtInfo.ActivityTel,
	}
}

func mapOrderItemForCEntityToPb(list []sqlc.Order, f func(sqlc.Order) *orderGrpc.OrderItemForCEntity) []*orderGrpc.OrderItemForCEntity {
	r := make([]*orderGrpc.OrderItemForCEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func preCheckBeforeOrdering(ctx context.Context, q *sqlc.Queries, s *OrderAPIService, cBrand *cache.BrandCachedValue, cActivity *cache.ActivityCachedValue, req *orderGrpc.PlaceOrderRequest) (err error) {

	activityID := req.ActivityId
	awardID := req.AwardId
	orderType := util.IfThenElse(awardID == 0, sqlc.EmOrderTypeSale, sqlc.EmOrderTypeRedeemAward).(sqlc.EmOrderType)

	if !cBrand.Ext.IsWxpayAvailable {
		err = fmt.Errorf("商家未配置收款账号，无法下单")
		return
	}

	// cActivity := s.cacher.FetchActivity(activityID)
	// if cActivity == nil {
	// 	err = fmt.Errorf("not found activity of activityID:%d", activityID)
	// 	return
	// }
	if util.IsAfterNow(cActivity.Begined) {
		err = fmt.Errorf("活动未开始:%d", activityID)
		return
	}
	if util.IsBeforeNow(cActivity.Ended) {
		err = fmt.Errorf("活动已结束:%d", activityID)
		return
	}
	if cActivity.ProcessStatus != sqlc.EmActivityProcessStatusProcessing {
		err = fmt.Errorf("活动不可用:%d", activityID)
		return
	}

	if cActivity.Owner == sqlc.EmActivityOwnerSpokesman {
		cActivity = s.cacher.FetchActivity(cActivity.ParentID)
	}

	if req.ProductAmount < int64(cActivity.MinimumPurchaseAmount) {
		err = fmt.Errorf("未满足单笔订单的购买起购金额")
		return
	}

	if req.DeliveryMode == string(enums.DeliveryModeSelfPickup) {
		if req.ProductAmount != req.Amount {
			err = fmt.Errorf("活动自提订单商品金额与总金额不匹配:%d", activityID)
			return
		}
		if req.ShippingFee != 0 {
			err = fmt.Errorf("活动自提订单运费应为0:%d", activityID)
			return
		}
	} else {
		if (req.ProductAmount + int64(req.ShippingFee)) != req.Amount {
			err = fmt.Errorf("活动配送订单商品金额、运费与总金额不匹配:%d", activityID)
			return
		}
	}

	if cActivity.MaxiumPurchaseFrequency > 0 {
		userID := req.UserId
		cnt, sqlErr := q.CountOrderAsUserBuy(ctx, sqlc.CountOrderAsUserBuyParams{
			UserID:     userID,
			ActivityID: activityID,
		})
		if sqlErr != nil {
			return sqlErr
		}
		if cnt >= int64(cActivity.MaxiumPurchaseFrequency) {
			return fmt.Errorf("到达活动参与次数上限")
		}
	}

	if orderType == sqlc.EmOrderTypeRedeemAward {
		// 检测是否有awardId对应的订单
		activityUserAward, sqlErr := q.GetActivityUserAward(ctx, awardID)
		if sqlErr != nil {
			err = sqlErr
			return
		}
		if activityUserAward.IsRedeemed {
			return fmt.Errorf("已兑奖")
		}
		// 正常,需要check存在的order
		if activityUserAward.OrderID.Valid {
			redeemOrder, sqlErr := q.GetOrder(ctx, activityUserAward.OrderID.Int64)
			if sqlErr != nil {
				err = sqlErr
				return
			}
			if util.IsAfterNow(redeemOrder.PaymentDeadlineAt) {
				return fmt.Errorf("兑奖订单已存在,请去订单详情页支付")
			}
		}
	}

	return
}

func genPlaceOrderParams(ctx context.Context, q *sqlc.Queries, s *OrderAPIService, cBrand *cache.BrandCachedValue, cActivity *cache.ActivityCachedValue, req *orderGrpc.PlaceOrderRequest, transMode enums.EnumTransModel) (
	createOrderParams sqlc.CreateOrderParams,
	upsertOrderDetailParams []sqlc.UpsertOrderDetailParams,
	orderExtInfoPtr *model.OrderExtInfo,
	err error) {

	brandID := req.BrandId
	activityID := req.ActivityId
	awardID := req.AwardId
	orderType := util.IfThenElse(awardID == 0, sqlc.EmOrderTypeSale, sqlc.EmOrderTypeRedeemAward).(sqlc.EmOrderType)

	var activityInventoryFreezeNo string
	if cActivity.Owner == sqlc.EmActivityOwnerSpokesman {
		cParentActivity := s.cacher.FetchActivity(cActivity.ParentID)
		if cParentActivity == nil {
			err = fmt.Errorf("not found activity of activityID:%d", cActivity.ParentID)
			return
		}
		activityInventoryFreezeNo = cParentActivity.InventoryFreezeNo
	} else {
		activityInventoryFreezeNo = cActivity.InventoryFreezeNo
	}

	warehouseID := req.WarehouseId
	cWarehouse := s.cacher.FetchWarehouse(warehouseID)
	if cWarehouse == nil {
		err = fmt.Errorf("not found warehouse of warehouseID:%d", warehouseID)
		return
	}

	skuProductWithSpecInfos, err := q.ListSkuProductWithSpecInfosByActivityID(ctx, activityID)
	if err != nil {
		return
	}

	mapOfSkuProductWithSpecInfos := util.SliceToMapString(util.ToGenericSlice(skuProductWithSpecInfos), func(m map[string]interface{}, v interface{}) {
		val := v.(sqlc.ListSkuProductWithSpecInfosByActivityIDRow)
		m[val.ProductSpecKey] = v
	})

	userID := req.UserId
	buyer, err := q.GetUser(ctx, userID)
	if err != nil {
		return
	}

	var details []*model.OrderDetailInExtInfo
	for _, item := range req.OrderDetails {
		k := fmt.Sprintf("%d-%d", item.ProductId, item.ProductSpecId)
		v := mapOfSkuProductWithSpecInfos[k].(sqlc.ListSkuProductWithSpecInfosByActivityIDRow)

		details = append(details, &model.OrderDetailInExtInfo{
			ProductID:           item.ProductId,
			ProductName:         v.ProductName,
			ProductSpecID:       item.ProductSpecId,
			ProductSpecKey:      k,
			ProductSpecName:     v.ProductSpecName,
			ProductWithSpecName: v.SkuName,
			StorageKey:          v.StorageKey,
			ProductPics:         v.Pics,
			Quantity:            item.Quantity,
			Price:               item.Price,
		})
	}
	orderExtInfoPtr = &model.OrderExtInfo{
		BrandName:                 cBrand.Name,
		BrandPic:                  cBrand.Pic,
		BrandTel:                  cBrand.Tel,
		ActivityOwner:             string(cActivity.Owner),
		ActivityName:              cActivity.Name,
		ActivityTel:               cActivity.Tel,
		ActivityInventoryFreezeNo: activityInventoryFreezeNo,
		BuyerNickName:             buyer.NickName.String,
		BuyerPic:                  buyer.Pic.String,
		BuyerTel:                  buyer.Mobile.String,
		WarehouseID:               req.WarehouseId,
		WarehouseInfo: model.WarehouseInfo{
			Name:    cWarehouse.Name,
			Address: cWarehouse.Address,
			Lat:     cWarehouse.Lat,
			Lng:     cWarehouse.Lng,
			Linkman: cWarehouse.Linkman,
			Tel:     cWarehouse.Tel,
		},
		Details: details,
	}

	if cActivity.StoreID.Valid {
		cStore := s.storeService.GetCache(cActivity.StoreID.Int64)
		orderExtInfoPtr.StoreName = cStore.Name
		orderExtInfoPtr.StorePic = cStore.Pic
		orderExtInfoPtr.StoreTel = cStore.Tel
	}

	if orderType == sqlc.EmOrderTypeRedeemAward {
		orderExtInfoPtr.AwardID = awardID
	}

	if cActivity.Owner == sqlc.EmActivityOwnerSpokesman {
		cParentActivity := s.cacher.FetchActivity(cActivity.ParentID)
		if cParentActivity == nil {
			err = fmt.Errorf("not found parent activity of activityID:%d", cActivity.ParentID)
			return
		}
		orderExtInfoPtr.ParentActivityOwner = string(cParentActivity.Owner)
		orderExtInfoPtr.ParentActivityName = cParentActivity.Name
		orderExtInfoPtr.ParentActivityTel = cParentActivity.Tel
	}

	extInfo, marshalErr := json.Marshal(orderExtInfoPtr)
	if marshalErr != nil {
		err = marshalErr
		return
	}

	var productIDs []int64
	serialNumber := s.orderService.GenerateOrderNumber(0, userID)
	for _, item := range orderExtInfoPtr.Details {
		itemInfo, marshalErr := json.Marshal(item)
		if marshalErr != nil {
			err = marshalErr
			return
		}
		upsertOrderDetailParam := sqlc.UpsertOrderDetailParams{
			ProductID:      item.ProductID,
			ProductSpecID:  sqlc.NInt64FromInt64(item.ProductSpecID),
			ProductSpecKey: item.ProductSpecKey,
			ItemInfo:       json.RawMessage(itemInfo),
			Quantity:       item.Quantity,
			Price:          item.Price,
			Amount:         int64(item.Quantity * item.Price),
		}
		upsertOrderDetailParams = append(upsertOrderDetailParams, upsertOrderDetailParam)
		productIDs = append(productIDs, item.ProductID)
	}

	// 判定是否需要分账给平台, 目前全部不用,将来分商户
	needProfitToPlatformCommission := false

	// 判定分销佣金是否分账的条件 1是分销门店的订单 2订单明细商品匹配品牌分销供货商品设置
	isFromActivityOfDistributeStore := cActivity.Owner == sqlc.EmActivityOwnerStore && cActivity.DistributeID.Valid
	var isAnyProductMatchDistributeProductWithPricePercentOff = false
	s.slog.Infof("isFromActivityOfDistributeStore %v, check brand_distribute_product to brandID => %d", isFromActivityOfDistributeStore, brandID)
	if isFromActivityOfDistributeStore && cActivity.DistributeID.Valid {
		isAnyProductMatchDistributeProductWithPricePercentOff, err = q.CheckExistNormalBrandDistributeProductsByBrandIDAndProductIDs(ctx,
			sqlc.CheckExistNormalBrandDistributeProductsByBrandIDAndProductIDsParams{
				BrandID:    brandID,
				ProductIDs: productIDs,
			})
		if err != nil {
			return
		}
	}
	needProfitToDistributeCommission := isFromActivityOfDistributeStore && isAnyProductMatchDistributeProductWithPricePercentOff

	parentActivityID := cActivity.ParentID
	// 判定代言奖励金是否分账的条件 1是代言活动的订单 2订单明细商品匹配活动帮卖的奖励设置
	isFromActivityOfSpokesman := cActivity.Owner == sqlc.EmActivityOwnerSpokesman
	var isAnyProductMatchBonusSettings = false
	s.slog.Infof("isFromActivityOfSpokesman %v, check bonusSettings to activityID => %d", isFromActivityOfSpokesman, parentActivityID)
	if isFromActivityOfSpokesman && parentActivityID > 0 {
		isAnyProductMatchBonusSettings, err = q.CheckExistNormalActivityConsignmentBonusSettingsByActivityIDAndProductIDs(ctx,
			sqlc.CheckExistNormalActivityConsignmentBonusSettingsByActivityIDAndProductIDsParams{
				ActivityID: parentActivityID,
				Column2:    productIDs,
			})
		if err != nil {
			return
		}
	}
	needProfitToBonus := isFromActivityOfSpokesman && isAnyProductMatchBonusSettings
	isDistributorOrder := cActivity.DistributeID.Valid
	
	createOrderParams = sqlc.CreateOrderParams{
		SerialNumber:                     serialNumber,
		BrandID:                          req.BrandId,
		StoreID:                          cActivity.StoreID,
		DistributorID:                    cActivity.DistributeID,
		DistributorUserID:                sqlc.NInt64FromInt64(util.IfThenElse(!isDistributorOrder, int64(0), cActivity.PubUserID).(int64)),
		ActivityID:                       req.ActivityId,
		RootActivityID:                   sqlc.NInt64FromInt64(cActivity.RootID),
		ParentActivityID:                 sqlc.NInt64FromInt64(parentActivityID),
		UserID:                           userID,
		UserOpenID:                       req.UserOpenId,
		ShareUserID:                      sqlc.NInt64FromInt64(req.ShareUserId),
		SpokesmanID:                      sqlc.NInt64FromInt64(cActivity.SpokesmanID),
		SpokesmanUserID:                  sqlc.NInt64FromInt64(util.IfThenElse(cActivity.SpokesmanID == 0, int64(0), cActivity.PubUserID).(int64)),
		OrderType:                        string(orderType),
		TransModel:                       string(transMode),
		OrderStatus:                      string(enums.OrderStatusCreated),
		ExtInfo:                          json.RawMessage(extInfo),
		DeliveryMode:                     req.DeliveryMode,
		Remark:                           sqlc.NSFromString(req.Remark),
		ShippingAddress:                  sqlc.NRawMessageFromRawMessage(json.RawMessage(req.ShippingAddress)),
		ShippingFee:                      req.ShippingFee,
		ProductAmount:                    req.ProductAmount,
		Amount:                           req.Amount,
		NeedProfitToPlatformCommission:   needProfitToPlatformCommission,
		NeedProfitToDistributeCommission: needProfitToDistributeCommission,
		NeedProfitToBonus:                needProfitToBonus,
	}

	return
}

/****************************************************************************************/
/*                               order entity of cmd                                    */
/****************************************************************************************/

// PlaceOrder 用户下单
func (s *OrderAPIService) PlaceOrder(ctx context.Context, req *orderGrpc.PlaceOrderRequest) (res *orderGrpc.PlaceOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->PlaceOrder:%v", req)
	res = &orderGrpc.PlaceOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var order sqlc.Order
	var normalOrderDetailWithProductAndSpecInfos []sqlc.ListNormalOrderDetailWithProductAndSpecInfosByOrderSerialNumberRow
	var payment sqlc.Payment
	var createOrderParams sqlc.CreateOrderParams
	var upsertOrderDetailParams []sqlc.UpsertOrderDetailParams
	var orderExtInfoPtr *model.OrderExtInfo
	var transactionInfo *orderGrpc.TransactionInfo

	// 目前交易模型针对零售品 默认就是用下单+支付合并,履约独立的交易模型
	transMode := enums.TransModelOrderingPaymentMergeEnforcementIndependant

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		activityID := req.ActivityId
		brandID := req.BrandId

		cActivity := s.cacher.FetchActivity(activityID)
		if cActivity == nil {
			err = fmt.Errorf("not found activity of activityID:%d", activityID)
			return
		}

		cBrand := s.cacher.FetchBrand(brandID)
		if cBrand == nil {
			err = fmt.Errorf("not found brand of brandID:%d", brandID)
			return
		}

		err = preCheckBeforeOrdering(ctx, q, s, cBrand, cActivity, req)
		if err != nil {
			return err
		}

		createOrderParams, upsertOrderDetailParams, orderExtInfoPtr, err = genPlaceOrderParams(ctx, q, s, cBrand, cActivity, req, transMode)
		if err != nil {
			return err
		}

		order, err = s.orderService.CreateOrder(ctx, q, createOrderParams, upsertOrderDetailParams, orderExtInfoPtr)
		if err != nil {
			return err
		}

		if order.OrderType == string(sqlc.EmOrderTypeRedeemAward) {
			// 兑奖订单需要更新兑奖记录
			err = s.activityService.UpdateUserAwardSinceRedeemAwardOrderCreated(ctx, q, &order)
			if err != nil {
				return err
			}
		}
		// 查询 保证details能获取到product和spec的信息 deprecete 从order.ext_info里提取detail
		// normalOrderDetailWithProductAndSpecInfos, err = q.ListNormalOrderDetailWithProductAndSpecInfosByOrderSerialNumber(ctx, order.SerialNumber)
		// if err != nil {
		// 	return err
		// }
		// slog.Infof("3 查询订单明细扩展 ok")

		// 用户侧订单与仓库侧创建冻结单必须一个事务,扣减库存,
		inventoryFreezeOrderNo, err := s.orderService.CreateInventoryFreezeOrderForC(ctx, &order, normalOrderDetailWithProductAndSpecInfos, req.WarehouseId)
		if err != nil {
			return err
		}
		slog.Infof("3 创建仓库侧C端冻结单 ok")

		order, err = q.UpdateOrderInventoryFreezeOrderNo(ctx, sqlc.UpdateOrderInventoryFreezeOrderNoParams{
			ID:                     order.ID,
			InventoryFreezeOrderNo: sqlc.NSFromString(inventoryFreezeOrderNo),
		})
		if err != nil {
			return err
		}
		slog.Infof("4 更新冻结单号到本地 ok")

		payment, err = q.UpsertPayment(ctx, sqlc.UpsertPaymentParams{
			BrandID:           order.BrandID,
			OrderID:           order.ID,
			OrderSerialNumber: order.SerialNumber,
			Amount:            order.Amount,
		})
		if err != nil {
			return err
		}
		slog.Infof("5 创建本地支付单 ok")

		transactionInfoStr, err := s.paymentService.Pay(ctx, q, paymentService.PayParam{
			TransMode:  transMode,
			OrderPtr:   &order,
			PaymentPtr: &payment,
		})

		if err != nil {
			return err
		}
		slog.Infof("6 获取支付信息 ok")

		transactionInfo = &orderGrpc.TransactionInfo{}
		err = json.Unmarshal(transactionInfoStr, transactionInfo)
		if err != nil {
			return fmt.Errorf("unmarshal ext_info失败:%s", err.Error())
		}

		err = s.userService.UpdateStatSinceOrderCreated(ctx, q, &order)
		if err != nil {
			return err
		}
		slog.Infof("7 新订单更新到(UserStat) ok")

		if !model.CheckActivityCountOfUserInvolvedByUserProcedure(cActivity.Type) {
			err = s.activityService.UpdateActivityExposureStatSinceOrderCreated(ctx, q, activityID)
			if err != nil {
				return err
			}
			slog.Infof("7.1 交易类新订单更新到(ActivityExposureStat) ok")
		}

		err = s.activityService.UpdateActivitySkuFreezeQuantitySinceOrderCreatedWithLock(ctx, q, &order)
		if err != nil {
			return err
		}
		slog.Infof("8 新订单更新到(ActivitySku) ok")
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	res.Order = transformOrderEntityToPb(orderExtInfoPtr, nil)(order)
	res.TransactionInfo = transactionInfo
	return
}

// RepayOrder 用户对未支付单进行支付
func (s *OrderAPIService) RepayOrder(ctx context.Context, req *orderGrpc.RepayOrderRequest) (res *orderGrpc.RepayOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->RepayOrder:%v", req)
	res = &orderGrpc.RepayOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	var transactionInfoStr []byte

	orderSerialNumber := req.OrderSerialNumber
	userID := req.UserId

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err := q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}

		if order.OrderStatus != string(enums.OrderStatusCreated) && order.OrderStatus != string(enums.OrderStatusPending) {
			return fmt.Errorf("订单状态不允许重新支付")
		}

		if order.UserID != userID {
			err = fmt.Errorf("订单不属于用户:%d", userID)
			return
		}

		transactionInfoStr, err = s.paymentService.Repay(ctx, q, paymentService.RepayParam{
			OrderSerialNumber: req.OrderSerialNumber,
		})
		return
	})

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	transactionInfo := &orderGrpc.TransactionInfo{}
	err = json.Unmarshal(transactionInfoStr, transactionInfo)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("unmarshal ext_info失败:%s", err.Error()),
		}
		return

	}
	res.TransactionInfo = transactionInfo
	return
}

// CancelOrder 用户撤销订单
func (s *OrderAPIService) CancelOrder(ctx context.Context, req *orderGrpc.CancelOrderRequest) (res *orderGrpc.CancelOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->CancelOrder:%v", req)
	res = &orderGrpc.CancelOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var order sqlc.Order

	orderSerialNumber := req.OrderSerialNumber
	userID := req.UserId

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err = q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}
		slog.Infof("1 根据订单号获取订单 ok")

		if order.OrderStatus != string(enums.OrderStatusCreated) && order.OrderStatus != string(enums.OrderStatusPending) {
			err = fmt.Errorf("订单状态不允许撤销")
			return
		}

		if order.UserID != userID {
			err = fmt.Errorf("订单不属于用户:%d", userID)
			return
		}

		err = s.orderService.CancelOrder(ctx, q, orderService.CancelOrderParam{
			OrderID:      order.ID,
			CancelReason: req.CancelReason,
		})
		if err != nil {
			return err
		}
		slog.Infof("2 撤销订单 ok")

		_, sqlErr := q.GetPaymentByOrderSerialNumber(ctx, order.SerialNumber)
		if sqlErr != nil {
			if sqlErr == sql.ErrNoRows {
				// 没有本地支付单,(可能是只下单,这个错误应该当成一个逻辑分支,不用报错)
				slog.Infof("3 没有本地支付单,(可能是只下单,这个错误应该当成一个逻辑分支,不用报错)")
			} else {
				err = sqlErr
				return
			}
		} else {
			slog.Infof("3-1 根据订单号获取本地支付单 ok")
			err = s.paymentService.Close(ctx, q, paymentService.CloseParam{OrderPtr: &order})
			if err != nil {
				return err
			}
			slog.Infof("3-2 撤销本地支付单 ok")
		}

		err = s.activityService.UpdateActivitySkuFreezeQuantitySinceOrderCancelledWithLock(ctx, q, &order)
		if err != nil {
			return err
		}
		slog.Infof("4 新订单更新到(ActivitySku) ok")

		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	return
}

// PrepareOrder 商家订单备货
func (s *OrderAPIService) PrepareOrder(ctx context.Context, req *orderGrpc.PrepareOrderRequest) (res *orderGrpc.PrepareOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->PrepareOrder:%v", req)
	res = &orderGrpc.PrepareOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	var order sqlc.Order

	orderSerialNumber := req.OrderSerialNumber
	brandID := req.BrandId

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err = q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}
		slog.Infof("1 根据订单号获取订单 ok")

		if order.OrderStatus != string(enums.OrderStatusPayed) {
			return fmt.Errorf("订单状态不允许%s,应为payed", order.OrderStatus)
		}
		if order.DeliveryMode != string(enums.DeliveryModeSelfPickup) {
			return fmt.Errorf("订单配送方式不允许")
		}

		if order.BrandID != brandID {
			err = fmt.Errorf("订单单不属于请求的品牌:%d", brandID)
			return
		}

		err = s.orderService.PrepareOrder(ctx, q, orderService.PrepareOrderParam{
			OrderPtr: &order,
			BrandID:  order.BrandID,
		})

		if err != nil {
			return err
		}

		slog.Infof("1 商家订单备货 ok")

		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	return
}

// PickOrder 商家订单提货确认
func (s *OrderAPIService) PickOrder(ctx context.Context, req *orderGrpc.PickOrderRequest) (res *orderGrpc.PickOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->PickOrder:%v", req)
	res = &orderGrpc.PickOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	orderSerialNumber := req.OrderSerialNumber
	pickedCode := req.PickupCode
	isFromUser := pickedCode == ""
	picked := time.Now()

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err := q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}
		slog.Infof("1 根据订单号获取订单 ok")

		if order.OrderStatus != string(enums.OrderStatusPrepared) {
			return fmt.Errorf("订单状态不允许%s,应为prepared", order.OrderStatus)
		}
		if order.DeliveryMode != string(enums.DeliveryModeSelfPickup) {
			return fmt.Errorf("订单配送方式不允许")
		}
		if isFromUser {
			if order.UserID != req.GetUserId() {
				err = fmt.Errorf("订单单不属于请求的用户:%d", req.GetUserId())
				return
			}
		} else {
			if order.BrandID != req.GetBrandId() {
				err = fmt.Errorf("订单单不属于请求的品牌:%d", req.GetBrandId())
				return
			}
		}

		err = s.orderService.PickOrder(ctx, q, orderService.PickOrderParam{
			IsFromUser:        isFromUser,
			OrderSerialNumber: orderSerialNumber,
			Picked:            picked,
			PickupCode:        pickedCode,
		})
		if err != nil {
			return err
		}
		slog.Infof("2 本地确认自提订单 ok")
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	return
}

// DeliverOrder 商家订单发货
func (s *OrderAPIService) DeliverOrder(ctx context.Context, req *orderGrpc.DeliverOrderRequest) (res *orderGrpc.DeliverOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->DeliverOrder:%v", req)
	res = &orderGrpc.DeliverOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	var order sqlc.Order

	orderSerialNumber := req.OrderSerialNumber
	brandID := req.BrandId

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err = q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}
		slog.Infof("1 根据订单号获取订单 ok")

		if order.OrderStatus != string(enums.OrderStatusPayed) {
			return fmt.Errorf("订单状态不允许%s,应为payed", order.OrderStatus)
		}

		if order.DeliveryMode == string(enums.DeliveryModeSelfPickup) {
			return fmt.Errorf("订单配送方式不允许")
		}

		if order.BrandID != brandID {
			err = fmt.Errorf("订单单不属于请求的品牌:%d", brandID)
			return
		}

		// 等待远端grpc的发货确认接口

		err = s.orderService.DeliverOrder(ctx, q, orderService.DeliverOrderParam{
			OrderPtr:            &order,
			PlatformID:          req.Platform,
			PlatformOrderNumber: req.PlatformOrderNum,
			BrandID:             order.BrandID,
		})

		if err != nil {
			return err
		}

		slog.Infof("1 商家订单发货 ok")

		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	return
}

// ReceiveOrder 用户订单收货确认
func (s *OrderAPIService) ReceiveOrder(ctx context.Context, req *orderGrpc.ReceiveOrderRequest) (res *orderGrpc.ReceiveOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->ReceiveOrder:%v", req)
	res = &orderGrpc.ReceiveOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	orderSerialNumber := req.OrderSerialNumber
	received := time.Now()
	userID := req.UserId

	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		order, err := q.GetOrderBySerialNumber(ctx, orderSerialNumber)
		if err != nil {
			return err
		}
		slog.Infof("1 根据订单号获取订单 ok")

		if order.OrderStatus != string(enums.OrderStatusDelivered) {
			return fmt.Errorf("订单状态不允许%s,应为delivered", order.OrderStatus)
		}
		if order.DeliveryMode == string(enums.DeliveryModeSelfPickup) {
			return fmt.Errorf("订单配送方式不允许")
		}

		if order.UserID != userID {
			err = fmt.Errorf("订单不属于用户:%d", userID)
			return
		}

		err = s.orderService.ReceiveOrder(ctx, q, orderService.ReceiveOrderParam{
			OrderPtr: &order,
			Received: received,
		})
		if err != nil {
			return err
		}
		slog.Infof("2 本地确认发货订单 ok")
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	return
}

/****************************************************************************************/
/*                               order entity of query                                  */
/****************************************************************************************/

// GetOrder 获取订单
func (s *OrderAPIService) GetOrder(ctx context.Context, req *orderGrpc.GetOrderRequest) (res *orderGrpc.GetOrderResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->GetOrder:%v", req)
	res = &orderGrpc.GetOrderResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	var order sqlc.Order
	orderSerialNumber := req.GetSerialNumber()
	if orderSerialNumber != "" {
		order, err = q.GetOrderBySerialNumber(ctx, orderSerialNumber)
	} else {
		order, err = q.GetOrder(ctx, req.GetOrderId())
	}

	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == err, 404, 400),
			Msg:     err.Error(),
		}
		return
	}
	slog.Infof("1 获取订单 ok")

	orderExtInfo := &model.OrderExtInfo{}
	err = json.Unmarshal(order.ExtInfo, orderExtInfo)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     fmt.Sprintf("unmarshal ext_info失败:%s", err.Error()),
		}
		return
	}

	var enforcement sqlc.Enforcement
	if order.OrderStatus == string(sqlc.EmOrderStatusPrepared) ||
		order.OrderStatus == string(sqlc.EmOrderStatusDelivered) ||
		order.OrderStatus == string(sqlc.EmOrderStatusFinished) {
		enforcement, err = q.GetEnforcementByOrderSerialNumber(ctx, order.SerialNumber)
		if err != nil {
			res.OpRet = &message.OperationResult{
				Success: false,
				Code:    400,
				Msg:     err.Error(),
			}
			return
		}
	}

	res.Order = transformOrderEntityToPb(orderExtInfo, &enforcement)(order)
	return
}

// ListOrderItemsForC 分页获取多个订单(视角C)
func (s *OrderAPIService) ListOrderItemsForC(ctx context.Context, req *orderGrpc.ListOrderItemsForCRequest) (res *orderGrpc.ListOrderItemsForCResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->ListOrderItemsForC:%v", req)

	res = &orderGrpc.ListOrderItemsForCResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	userID := req.UserId
	isAll := req.IsAll
	orderStatuses := req.OrderStatuses

	total, err := q.CountOrdersAsUserSearcher(ctx, sqlc.CountOrdersAsUserSearcherParams{
		Created:       ts,
		UserID:        userID,
		IsAll:         isAll,
		OrderStatuses: orderStatuses,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	orders, err := q.ListOrdersAsUserSearcher(ctx, sqlc.ListOrdersAsUserSearcherParams{
		Limit:         req.Limit,
		Offset:        req.Offset,
		Created:       ts,
		UserID:        userID,
		IsAll:         isAll,
		OrderStatuses: orderStatuses,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	slog.Infof("total:%d,orders=>%d", total, len(orders))
	res.Total = total
	res.OrderItemsForC = mapOrderItemForCEntityToPb(orders, transformOrderItemForCEntityToPb)
	return
}

/****************************************************************************************/
/*                            orderJoins entity of helper                               */
/****************************************************************************************/

// OBSOLETE MARK 目前订单采用下单时的用户信息作为买家信息,不用关联的用户信息作为买家信息
/*
func transformOrderItemWithLatestBuyerInfoForSEntityToPb(o sqlc.ListOrderWithLatestBuyerInfosByUserIDAsSpokesmanRow) *orderGrpc.OrderItemForSEntity {
	orderExtInfo := &model.OrderExtInfo{}
	json.Unmarshal(o.ExtInfo, orderExtInfo)

	return &orderGrpc.OrderItemForSEntity{
		Id:            o.ID,
		Ordered:       sqlc.GoTimeToPBTimestamp(o.Ordered),
		SerialNumber:  o.SerialNumber,
		BrandId:       o.BrandID,
		ActivityId:    o.ActivityID,
		OrderStatus:   o.OrderStatus,
		DeliveryMode:  o.DeliveryMode,
		Amount:        o.Amount,
		OrderDetails:  mapOrderDetailEntityToPb(orderExtInfo.Details, transformOrderDetailEntityToPb),
		BrandName:     orderExtInfo.BrandName,
		BrandPic:      orderExtInfo.BrandPic,
		BrandTel:      orderExtInfo.BrandTel,
		ActivityName:  orderExtInfo.ActivityName,
		ActivityTel:   orderExtInfo.ActivityTel,
		BuyerNickName: o.BuyerNickName,
		BuyerPic:      o.BuyerPic,
	}
}

func mapOrderItemWithLatestBuyerInfoForSEntityToPb(list []sqlc.ListOrderWithLatestBuyerInfosByUserIDAsSpokesmanRow, f func(sqlc.ListOrderWithLatestBuyerInfosByUserIDAsSpokesmanRow) *orderGrpc.OrderItemForSEntity) []*orderGrpc.OrderItemForSEntity {
	r := make([]*orderGrpc.OrderItemForSEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformOrderItemWithLatestBuyerInfoForBEntityToPb(o sqlc.ListOrderWithLatestBuyerInfosByUserIDAsBrandRow) *orderGrpc.OrderItemForBEntity {
	orderExtInfo := &model.OrderExtInfo{}
	json.Unmarshal(o.ExtInfo, orderExtInfo)

	return &orderGrpc.OrderItemForBEntity{
		Id:            o.ID,
		Ordered:       sqlc.GoTimeToPBTimestamp(o.Ordered),
		SerialNumber:  o.SerialNumber,
		BrandId:       o.BrandID,
		ActivityId:    o.ActivityID,
		OrderStatus:   o.OrderStatus,
		DeliveryMode:  o.DeliveryMode,
		Amount:        o.Amount,
		OrderDetails:  mapOrderDetailEntityToPb(orderExtInfo.Details, transformOrderDetailEntityToPb),
		BrandName:     orderExtInfo.BrandName,
		BrandPic:      orderExtInfo.BrandPic,
		BrandTel:      orderExtInfo.BrandTel,
		ActivityName:  orderExtInfo.ActivityName,
		ActivityTel:   orderExtInfo.ActivityTel,
		BuyerNickName: o.BuyerNickName,
		BuyerPic:      o.BuyerPic,
	}
}

func mapOrderItemWithLatestBuyerInfoForBEntityToPb(list []sqlc.ListOrderWithLatestBuyerInfosByUserIDAsBrandRow, f func(sqlc.ListOrderWithLatestBuyerInfosByUserIDAsBrandRow) *orderGrpc.OrderItemForBEntity) []*orderGrpc.OrderItemForBEntity {
	r := make([]*orderGrpc.OrderItemForBEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}
*/

/****************************************************************************************/
/*                            orderJoins entity of query                                */
/****************************************************************************************/

// OBSOLETE MARK 目前订单采用下单时的用户信息作为买家信息,不用关联的用户信息作为买家信息

/*
// ListOrderItemsWithLatestBuyerInfoForS 分页获取多个订单(视角S)
func (s *OrderAPIService) ListOrderItemsWithLatestBuyerInfoForS(ctx context.Context, req *orderGrpc.ListOrderItemsForSRequest) (res *orderGrpc.ListOrderItemsForSResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->ListOrderItemsWithLatestBuyerInfoForS:%v", req)

	res = &orderGrpc.ListOrderItemsForSResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q

	total, err := q.CountOrderWithLatestBuyerInfosByUserIDAsSpokesman(ctx, sqlc.NInt64FromInt64(req.UserId))
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	orders, err := q.ListOrderWithLatestBuyerInfosByUserIDAsSpokesman(ctx, sqlc.ListOrderWithLatestBuyerInfosByUserIDAsSpokesmanParams{
		Limit:           req.Limit,
		Offset:          req.Offset,
		SpokesmanUserID: sqlc.NInt64FromInt64(req.UserId),
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.OrderItemsForS = mapOrderItemWithLatestBuyerInfoForSEntityToPb(orders, transformOrderItemWithLatestBuyerInfoForSEntityToPb)
	return
}

// ListOrderItemsWithLatestBuyerInfoForB 分页获取多个订单(视角B)
func (s *OrderAPIService) ListOrderItemsWithLatestBuyerInfoForB(ctx context.Context, req *orderGrpc.ListOrderItemsForBRequest) (res *orderGrpc.ListOrderItemsForBResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("orderImp->ListOrderItemsWithLatestBuyerInfoForB:%v", req)

	res = &orderGrpc.ListOrderItemsForBResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	total, err := s.dao.Q.CountOrderWithLatestBuyerInfosByUserIDAsBrand(ctx, req.BrandId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	orders, err := s.dao.Q.ListOrderWithLatestBuyerInfosByUserIDAsBrand(ctx, sqlc.ListOrderWithLatestBuyerInfosByUserIDAsBrandParams{
		Limit:   req.Limit,
		Offset:  req.Offset,
		BrandID: req.BrandId,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.OrderItemsForB = mapOrderItemWithLatestBuyerInfoForBEntityToPb(orders, transformOrderItemWithLatestBuyerInfoForBEntityToPb)
	return
}
*/
